import fs from "fs";
import path from "path";
import { AppCfg, miscCfg, SvrInfo } from "./util/defines";
import { AppIniter } from "./AppIniter";
import { BackendServer } from "./server/BackendServer";
import { FrontendServer } from "./server/FrontendServer";
import { FrontendSession } from "./session/FrontendSession";
import { logger } from "./util/logger";
import { Master } from "./server/Master";
import { RpcService } from "./rpc/RpcService";

/**
 * 服务器全局应用程序
 */
export class Application {

    /** 可设置的配置 */
    miscCfg: typeof miscCfg = miscCfg;
    /** 服务器是否已经启动 */
    isStarted = false;
    /** 服务器是否正在停止 */
    isStopping = false;
    /** 项目主程序代码所在目录路径 */
    base = require.main.path;
    /** 项目主程序代码文件路径 */
    main = require.main.filename;
    /** 运行环境 */
    env = "development";
    /** 是否 ts-node 环境 */
    isTs: boolean;
    /** 启动时间 */
    startTime = 0;
    /** 当前服务器信息 */
    svr: SvrInfo;
    /** 当前服务器类型 */
    stype: string;
    /** 主服务器配置 */
    masterCfg: SvrInfo;

    /** 服务器配置 */
    svrCfg: { [stype: string]: SvrInfo[] };
    /** 服务器配置id映射 */
    svrCfgIdMap: { [sid: string]: SvrInfo };
    /** 所有运行中的服务器 */
    svrs: { [stype: string]: SvrInfo[] } = {};
    /** 所有运行中的服务器id映射 */
    svrIdMap: { [sid: string]: SvrInfo } = {};

    /** 消息路由配置 [stype,msgHandler,msgHandlerFunc] */
    msgCfg: { [msgId: string]: string[] };

    /** 是否是主服务器 */
    isMaster: boolean;
    /** 主服务器 */
    master: Master;
    /** 前端服务器 */
    frontendSvr: FrontendServer;
    /** 后端服务器 */
    backendSvr: BackendServer;

    /** Rpc服务 */
    rpcService: RpcService;
    /** 日志输出 */
    logger = logger.init(this);

    /** 客户端数量 */
    clientCount = 0;
    /** 所有客户端 */
    clients: { [uid: number]: FrontendSession } = {};

    /** 服务器路由 */
    svrRouters: { [stype: string]: (sess: FrontendSession, svrCfgs: SvrInfo[]) => SvrInfo } = {};


    /**
     * 远程调用
     * @param sid 不填或为"*"时,会广播给Rpc对应类型的所有服务器且不接收返回
     * @param notify 仅通知,不接收返回
     * @returns
     */
    rpc: (sid: string, notify?: boolean) => Rpc;

    constructor(cfg: AppCfg) {
        new AppIniter(this, cfg);
    }

    /**
     * 启动服务器
     */
    start(onStart?: () => void) {
        if (this.isStarted) {
            console.error("服务器已经启动过了");
            return;
        }
        this.isStarted = true;
        this.startTime = Date.now();
        if (this.stype === "master") {
            this.master = new Master(this);
        } else {
            this.rpcService = new RpcService(this,
                //onStart
                () => {
                    if (this.svr.isFrontend) {
                        this.frontendSvr = new FrontendServer(this, onStart);
                    } else {
                        this.backendSvr = new BackendServer(this, onStart);
                    }
                });
        }
    }

    /**
     * 获取运行中的指定id服务器的信息
     * @param sid 
     * @returns 
     */
    getSvr(sid: string) {
        return this.svrIdMap[sid];
    }

    /**
     * 指定id的服务器是否运行中
     * @param sid 
     * @returns 
     */
    hasSvr(sid: string) {
        return !!this.getSvr(sid);
    }

    /**
     * 获取指定服务器类型所有的sid
     * @param stype 
     */
    getSidsByStype(stype: string) {
        let sids: string[] = [];
        if (this.svrs[stype]) {
            for (let svr of this.svrs[stype]) {
                sids.push(svr.id);
            }
        }
        return sids;
    }

    /**
     * 获取客户端
     * @param id 
     * @returns 
     */
    getClient(id: number) {
        return this.clients[id];
    }

    /**
     * 客户端是否在线
     * @param uid 
     * @returns 
     */
    hasClient(id: number) {
        return !!this.clients[id];
    }

    /**
     * 设置服务器路由
     * @param stype 
     * @param router 
     */
    setSvrRouter(stype: string, router: (sess: FrontendSession, svrCfgs: SvrInfo[]) => SvrInfo) {
        this.svrRouters[stype] = router;
    }

    /**
     * 通过路由获取服务器
     * @param stype 
     * @param sess 
     * @returns 
     */
    getSvrWidthRouter(stype: string, sess: FrontendSession) {
        return this.svrRouters[stype](sess, this.svrCfg[stype]);
    }

    /**
     * 重载消息路由配置
     * @param reloadPath 
     */
    reloadMsgCfg(reloadPath = miscCfg.reloadMsgCfgPath) {
        if (!reloadPath || !fs.existsSync(reloadPath)) {
            logger.error("重载消息路由配置的路径未设置或不存在", this, this.reloadMsgCfg);
            return false;
        }
        try {
            let cfgPath = path.resolve(this.base, reloadPath);
            delete require.cache[cfgPath];
            let req = require(cfgPath);
            let cfg = req.default || req;
            delete require.cache[cfgPath];
            for (let msgId in cfg) {
                this.msgCfg[msgId] = cfg[msgId].split(".");
            }
            logger.info("已重载消息路由配置", this, this.reloadMsgCfg);
            return true;
        } catch (err: any) {
            logger.error("重载消息路由配置失败: " + err.stack, this, this.reloadMsgCfg);
        }
        return false;
    }

}